#include <iostream>
#include <memory>

// 以笔记本电脑为例，给出建造者模式的实现代码。

class Computer 
{
public:
    void showParameters()
    {
        std::string msg = "Parameters of the computer:\n";
        msg += "Board: " + _board + "\n";
        msg += "Display: " + _display + "\n";
        msg += "OS: " + _os;
        std::cout << msg << std::endl;
    }

    void setBoard(std::string board) { _board = board; }
    void setDisplay(std::string display) { _display = display; }
    virtual void setOS() = 0;

protected:
    std::string _board;  // 所有电脑都有主板
    std::string _display;  // 所有电脑都有显示屏
    std::string _os;  // 不同型号的电脑可能有不同的操作系统
};

class MacBook : public Computer 
{
public:
    void setOS() override 
    {
        _os = "Mac OS"; 
    }
};

class Builder
{
public:
    virtual void buildBoard(std::string board) = 0;
    virtual void buildDisplay(std::string display) = 0;
    virtual void buildOS() = 0;
    virtual std::shared_ptr<Computer> getComputer() = 0;
};

class MacBookBuilder : public Builder 
{
public:
    MacBookBuilder() : _computer(std::make_shared<MacBook>()) {}

    void buildBoard(std::string board) override 
    {
        _computer->setBoard(board);
    }

    void buildDisplay(std::string display) override 
    {
        _computer->setDisplay(display);
    }

    void buildOS() override 
    {
        _computer->setOS();
    }

    std::shared_ptr<Computer> getComputer() override 
    {
        return _computer;
    }

private:
    std::shared_ptr<Computer> _computer;
};

// 指挥者 -- 用于指定建造的顺序
class Director
{
public:
    Director(Builder* builder) : _builder(builder) {}

    void construct(std::string board, std::string display) 
    {
        _builder->buildBoard(board);
        _builder->buildDisplay(display);
        _builder->buildOS();
    }
private:
    std::shared_ptr<Builder> _builder;
};

void test()
{
    Builder* builder = new MacBookBuilder() ;
    std::unique_ptr<Director> director = std::make_unique<Director>(builder);
    director->construct("M1", "Retina");
    std::shared_ptr<Computer> computer = builder->getComputer();
    computer->showParameters();
}

int main()
{
    test();
    return 0;
}